package kz.kstu.scantest.desktop.ui.dialog;

import kz.kstu.scantest.business.entity.data.*;
import kz.kstu.scantest.business.entity.data.FieldNameEnum;
import kz.kstu.scantest.business.entity.data.SubjectEnum;
import kz.kstu.scantest.business.util.StringUtil;
import kz.kstu.scantest.desktop.api.FormDataTableModel;
import kz.kstu.scantest.desktop.util.GUIUtils;

import javax.swing.*;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.text.JTextComponent;
import java.awt.*;
import java.awt.event.*;
import java.util.Arrays;

public class EditFormDataDialog extends JDialog {
    private static final int WIDTH = 800;
    private static final int HEIGHT = 210;
    private static final int FIRST_COLUMN_MIN_WIDTH = 120;

    private static final java.util.List<Character> AVAILABLE_KEY =
            Arrays.asList('A', 'B', 'C', 'D', 'E', 'a', 'b', 'c', 'd', 'e');
    private static final int VARIANT_LENGTH = 4;
    private static final int INITIALS_TEXT_FIELD_LENGTH = 5;
    private static final int SURNAME_TEXT_FIELD_LENGTH = 17;

    private JPanel rootPanel;
    private JButton buttonOK;
    private JButton buttonCancel;
    private JTable formDataTable;
    private JTextField surnameField;
    private JTextField initialsField;
    private JTextField variantField;
    private FormData formData;
    private int state;
    private JTextField answerCellEditField;
    private JComboBox subjectCellEditCombo;

    public EditFormDataDialog(Frame owner) {
        super(owner, true);
    }

    public FormData getFormData() {
        return formData;
    }

    public int editFormData(FormData formData) {
        this.formData = formData;
        initialize();
        return state;
    }

    private void initialize() {
        initStaticComponent();
        initListeners();
        initCellEditors();
        initData();
        GUIUtils.centerAndShow(this);
    }

    private void initData() {
        surnameField.setText(formData.getSurname());
        initialsField.setText(formData.getInitials());
        variantField.setText(formData.getVariant());
    }

    private void initStaticComponent() {
        answerCellEditField = new JTextField();
        subjectCellEditCombo = new JComboBox(SubjectEnum.values());
        FormDataTableModel formDataTableModel = new FormDataTableModel(formData);
        formDataTable.setModel(formDataTableModel);
        formDataTable.getTableHeader().setReorderingAllowed(false);
        TableColumn firstColumn = formDataTable.getColumnModel().getColumn(0);
        firstColumn.setMinWidth(FIRST_COLUMN_MIN_WIDTH);
        setContentPane(rootPanel);
        getRootPane().setDefaultButton(buttonOK);
        this.setSize(WIDTH, HEIGHT);
        this.setResizable(false);
    }

    private void initCellEditors() {
        initSubjectCellEditor();
        initAnswerCelEditor();
    }

    private void initSubjectCellEditor() {
        DefaultCellEditor subjectCellEditor = new DefaultCellEditor(subjectCellEditCombo);
        TableColumn subjectColumn = formDataTable.getColumnModel().getColumn(0);
        subjectColumn.setCellEditor(subjectCellEditor);
        SubjectData fifthSubjectData = formData.getSubjects().get(FieldNameEnum.FIFTH_SUBJECT);
        subjectCellEditCombo.setSelectedItem(fifthSubjectData.getSubjectEnum());
    }

    private void initAnswerCelEditor() {
        DefaultCellEditor cellEditor = new DefaultCellEditor(answerCellEditField);
        TableColumnModel columnModel = formDataTable.getColumnModel();
        for (int i = 1; i <= 25; i++) {
            TableColumn tableColumn = columnModel.getColumn(i);
            tableColumn.setCellEditor(cellEditor);
        }
    }

    private void initListeners() {
        buttonOK.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onOK();
            }
        });

        buttonCancel.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onCancel();
            }
        });

        this.addWindowListener(new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                onCancel();
            }
        });

        rootPanel.registerKeyboardAction(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                onCancel();
            }
        }, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);

        KeyListener answerKeyListener = new AnswerKeyListener();
        answerCellEditField.addKeyListener(answerKeyListener);
        formDataTable.addKeyListener(answerKeyListener);
        variantField.addKeyListener(new MaxLengthKeyListener(VARIANT_LENGTH));
        variantField.addKeyListener(new DigitKeyListener());
        initialsField.addKeyListener(new MaxLengthKeyListener(INITIALS_TEXT_FIELD_LENGTH));
        surnameField.addKeyListener(new MaxLengthKeyListener(SURNAME_TEXT_FIELD_LENGTH));
    }

    private void onOK() {
        formData.setVariant(variantField.getText());
        formData.setSurname(surnameField.getText());
        formData.setInitials(initialsField.getText());
        state = JOptionPane.OK_OPTION;
        saveEditableCellValue();
        dispose();
    }

    private void saveEditableCellValue() {
        int colInx = formDataTable.getEditingColumn();
        int rowInx = formDataTable.getEditingRow();
        if (colInx > 0 && rowInx != -1) {
            formDataTable.setValueAt(answerCellEditField.getText(), rowInx, colInx);
        }
    }

    private void onCancel() {
        state = JOptionPane.CANCEL_OPTION;
        dispose();
    }

    private class AnswerKeyListener extends KeyAdapter {

        public void keyTyped(KeyEvent e) {
            char character = e.getKeyChar();
            if (AVAILABLE_KEY.contains(character)) {
                answerCellEditField.setText(StringUtil.EMPTY_STRING);
                e.setKeyChar(Character.toUpperCase(character));
            } else {
                e.consume();
            }
        }
    }

    private class DigitKeyListener extends KeyAdapter {

        public void keyTyped(KeyEvent e) {
            char character = e.getKeyChar();
            if (!Character.isDigit(character)) {
                e.consume();
            }
        }
    }

    private class MaxLengthKeyListener extends KeyAdapter {

        private int maxLength;

        public MaxLengthKeyListener(int maxLength) {
            this.maxLength = maxLength;
        }

        public void keyTyped(KeyEvent e) {
            JTextComponent textComponent = (JTextComponent) e.getSource();
            int selectedTextLength = textComponent.getSelectionEnd() - textComponent.getSelectionStart();
            if (textComponent.getText().length() >= maxLength && selectedTextLength == 0) {
                e.consume();
            }
        }
    }
}
